package validate

import (
	"errors"
	"github.com/gin-gonic/gin"
	"net/url"
	"reflect"
	"regexp"
)

// 正则集合
const (
	IDCard   = `^\d{15}|\d{18}$`                                                      // 身份证号
	Phone    = `^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$` // 手机号
	NUMBER   = `^[0-9]*$`                                                             // 数字
	NPLUSNUM = `^[1-9]\d*$`                                                           // 正整数
	NNUM     = `^\d+$`                                                                // 非负整数
	ZNUM     = `^[0-9]*$`                                                             // 整数
	CHINESE  = `^[\u4e00-\u9fa5]{0,}$`                                                // 汉字
	EMAIL    = `^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$`                        // 邮箱
	WWW      = `[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?`   // 域名
	LETTER   = `^[A-Za-z0-9]+$`                                                       // 数字和字母组成的字符串
	Sex      = `^男$|^女$`
	Bool     = `^true|^false$`
)

// 规则集合
const (
	R_ISNUMBER = "isNumber"
	R_NotEmpty = "notEmpty"
	R_NGEZERO  = "NGEZero" // 非负整数
	R_ITEMCODE = "ItemCode"
	R_SEX      = "sex"
	R_BOOL     = "bool"
)

// 初始化的ruleMap
var CustomizeMap = make(map[string]Rules)

// 获取postform
func GetPostForm(c *gin.Context) url.Values {
	_ = c.Request.ParseMultipartForm(32 << 20) // 32MB
	return c.Request.PostForm
}

// 规则初始化
func init() {
	// 分页
	_ = RegisterRule("PageVerify", Rules{
		"pageSize": {R_NGEZERO, R_NotEmpty},
		"pageNum":  {R_NGEZERO},
	})
	// id
	_ = RegisterRule("IdVerify", Rules{
		"id": {R_ITEMCODE, R_NotEmpty},
	})
	// 商品code
	_ = RegisterRule("CodeVerify", Rules{
		"code": {R_ISNUMBER},
	})
}

// 注册规则
func RegisterRule(key string, rule Rules) (err error) {
	if CustomizeMap[key] != nil {
		return errors.New(key + "已注册,无法重复注册")
	} else {
		CustomizeMap[key] = rule
		return nil
	}
}

// 数据约定,必须是该数组中的值
type In []interface{}

// 规则
type Rules map[string][]interface{}

// 定制规则
type RuleMap map[string]Rules

// 检验方法
/**
该版本只负责写了规则的参数校验，没写则通过校验
*/
func V2(param url.Values, rules Rules) error {
	//var errInfo map[string]interface{}
	typeOf := reflect.TypeOf(param)
	//valueOf := reflect.ValueOf(param)
	switch typeOf.Kind() {
	case reflect.Map:
		// 遍历规则 k:字段名string v:规则[]string
		for k, v := range rules {
			// 参数值
			if strv, ok := param[k]; !ok {
				continue
			} else {
				columValue := reflect.ValueOf(strv[0])
				columStr := columValue.String()

				// 得到参数值后，遍历规则
				for _, rule := range v {
					switch rule {
					// 非空
					case R_NotEmpty:
						if isBlank(columValue) {
							return errors.New(k + "不能为空")
						}
					case R_ISNUMBER:
						if !Regular(columStr, NUMBER) {
							return errors.New(k + "类型异常")
						}
					case R_SEX:
						if !Regular(columStr, Sex) {
							return errors.New(k + "不合法")
						}
					case R_BOOL:
						if !Regular(columStr, Bool) {
							return errors.New(k + "不合法")
						}
					case "isIDCard":
						if !Regular(strv[0], IDCard) {
							return errors.New("身份证格式有误")
						}
					case "isPhone":
						if !Regular(strv[0], Phone) {
							return errors.New("手机号格式有误")
						}
					case "length":
						if !Regular(strv[0], "") {
							return errors.New(k + "长度不在规定范围内")
						}
					case R_NGEZERO:
						if !Regular(strv[0], NNUM) {
							return errors.New(k + "参数有误！")
						}
					case R_ITEMCODE:
						if !Regular(strv[0], LETTER) {
							return errors.New("参数有误！")
						}
					default:
						continue
					}
				}
			}
		}
	case reflect.Struct:
		return errors.New("参数类型不符")
	default:

	}
	//fmt.Println(typeOf, valueOf)
	return nil
}

// 校验空值方法
func isBlank(value reflect.Value) bool {
	switch value.Kind() {
	case reflect.String:
		return value.Len() == 0
	case reflect.Bool:
		return !value.Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return value.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return value.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return value.Float() == 0
	case reflect.Interface, reflect.Ptr:
		return value.IsNil()
	}
	return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
}

// 正则校验
func Regular(val, reg string) bool {
	if regexp.MustCompile(reg).MatchString(val) {
		return true
	}
	return false
}
